package com.zhou.base.components.bs.common.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.google.common.collect.Lists;
import com.zhou.base.components.bs.common.model.BaseEntity;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;

@Slf4j
public class JSONUtils {


    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");

    private static ObjectMapper objectMapper = new ObjectMapper();

    static {
        //configure方法 配置一些需要的参数
        // 转换为格式化的json 显示出来的格式美化
//        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);

        //序列化的时候序列对象的那些属性  
        //JsonInclude.Include.NON_DEFAULT 属性为默认值不序列化 
        //JsonInclude.Include.ALWAYS      所有属性
        //JsonInclude.Include.NON_EMPTY   属性为 空（“”） 或者为 NULL 都不序列化 
        //JsonInclude.Include.NON_NULL    属性为NULL 不序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        //反序列化时,遇到未知属性会不会报错 
        //true - 遇到没有的属性就报错 false - 没有的属性不会管，不会报错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        //如果是空对象的时候,不抛异常  
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

        // 忽略 transient 修饰的属性
        objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);

        //修改序列化后日期格式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GTM+8"));
        objectMapper.setDateFormat(simpleDateFormat);

        //处理不同的时区偏移格式
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);


        JavaTimeModule javaTimeModule = new JavaTimeModule();   // 默认序列化没有实现，反序列化有实现
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATE_TIME_FORMATTER));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DATE_TIME_FORMATTER));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DATE_FORMATTER));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DATE_FORMATTER));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(TIME_FORMATTER));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(TIME_FORMATTER));
        javaTimeModule.addSerializer(byte[].class, new BytesSerializer(byte[].class));
        objectMapper.registerModule(javaTimeModule);
    }

    public static String toJson(Object object) {
        String s = null;
        try {
            s = objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            log.error("", e);
        }
        return s;
    }

    public static <T> T toObject(String json, Class<T> clazz) {
        T s = null;
        try {
            s = objectMapper.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            log.error("", e);
        }
        return s;
    }

    public static Object toObject(String json, Type type) {
        Object s = null;
        try {
            TypeReference typeReference = new TypeReference<Object>() {
                @Override
                public Type getType() {
                    return type;
                }
            };
            s = objectMapper.readValue(json, typeReference);
        } catch (JsonProcessingException e) {
            log.error("", e);
        }
        return s;
    }

    public static <T> T toObject(String json, TypeReference<T> typeReference) {
        T s = null;
        try {
            s = objectMapper.readValue(json, typeReference);
        } catch (JsonProcessingException e) {
            log.error("", e);
        }
        return s;
    }

    public static <T> List<T> toOList(String json, Class<T> clazz) {
        List<T> s = null;
        try {
            CollectionType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, clazz);
            s = objectMapper.readValue(json, javaType);
        } catch (JsonProcessingException e) {
            log.error("", e);
        }
        return s;
    }


    public static void main(String[] args) {
        String test1 = "周先锋";

        BaseEntity baseEntity = new BaseEntity();
        baseEntity.setCreatorId("setCreatorId");
        baseEntity.setCreatorName("setCreatorName");
        baseEntity.setCreatedTime(LocalDateTime.now());
        ArrayList<BaseEntity> users = Lists.newArrayList(baseEntity, baseEntity);
        String str = toJson(users);
        System.out.println("user json:" + str);

        String jsonStr = "[{\"creator_id\":\"" + test1.getBytes() + "\",\"creator_name\":\"setCreatorName\"," +
                "\"created_time\":\"2023-05-18 15:55:30\"},{\"creator_id\":\"setCreatorId\",\"creator_name\":\"setCreatorName\",\"created_time\":\"2023-05-18 15:55:30\"}]";
        List<BaseEntity> baseEntities = toOList(jsonStr, BaseEntity.class);
        System.out.println("user json:" + toJson(baseEntities));
    }

    public static class BytesSerializer extends StdSerializer<byte[]> {

        protected BytesSerializer(Class<byte[]> src) {
            super(src);
        }

        @Override
        public void serialize(byte[] value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeObject(new String(value));
            //String currentName = gen.getOutputContext().getCurrentName();
//        gen.writeStartObject();
//        gen.writeObjectField(currentName, new String(value));
//        gen.writeEndObject();

        }
    }

}
